/* 
*  Copyright (C) 2009-2010 WCG Project
*
*  This program is free software; you can redistribute it and/or modify it
*  under the terms of the GNU General Public License as published by the
*  Free Software Foundation; either version 2 of the License, or (at
*  your option) any later version.
*
*  This program is distributed in the hope that it will be useful, but
*  WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
*  General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program; if not, write to the Free Software Foundation,
*  Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*  In addition, as a special exception, the author gives permission to
*  link the code of this program with the Half-Life Game Engine ("HL
*  Engine") and Modified Game Libraries ("MODs") developed by Valve,
*  L.L.C ("Valve"). You must obey the GNU General Public License in all
*  respects for all of the code used other than the HL Engine and MODs
*  from Valve. If you modify this file, you may extend this exception
*  to your version of the file, but you are not obligated to do so. If
*  you do not wish to do so, delete this exception statement from your
*  version.
*/



/*
*	UTIL Functions - Basically helper functions
*/


stock UTIL_SetSize( ent, const Float:vMin[3], const Float:vMax[3] )
{
	engfunc( EngFunc_SetSize, ent, vMin, vMax )
}



stock UTIL_GetWeaponName( iWeapon, szWpnName[], len )
{
	switch ( iWeapon )
	{
		case CSW_KNIFE:			copy( szWpnName, len, "knife"		)

		case CSW_USP:           copy( szWpnName, len, "usp"			)
		case CSW_GLOCK18:       copy( szWpnName, len, "glock18"		)
		case CSW_DEAGLE:        copy( szWpnName, len, "deagle"		)
		case CSW_P228:          copy( szWpnName, len, "p228"		)
		case CSW_ELITE:         copy( szWpnName, len, "elite"		)
		case CSW_FIVESEVEN:     copy( szWpnName, len, "fiveseven"	)

		case CSW_M3:            copy( szWpnName, len, "m3"			)
		case CSW_XM1014:        copy( szWpnName, len, "xm1014"		)

		case CSW_MP5NAVY:       copy( szWpnName, len, "mp5navy"		)
		case CSW_TMP:           copy( szWpnName, len, "tmp"			)
		case CSW_P90:           copy( szWpnName, len, "p90"			)
		case CSW_MAC10:         copy( szWpnName, len, "mac10"		)
		case CSW_UMP45:         copy( szWpnName, len, "ump45"		)

		case CSW_AK47:          copy( szWpnName, len, "ak47"		)
		case CSW_SG552:         copy( szWpnName, len, "sg552"		)
		case CSW_M4A1:          copy( szWpnName, len, "m4a1"		)
		case CSW_AUG:           copy( szWpnName, len, "aug"			)
		case CSW_SCOUT:         copy( szWpnName, len, "scout"		)
		case CSW_AWP:           copy( szWpnName, len, "awp"			)
		case CSW_SG550:         copy( szWpnName, len, "sg550"		)
		case CSW_G3SG1:         copy( szWpnName, len, "g3sg1"		)

		case CSW_GALI:          copy( szWpnName, len, "galil"		)
		case CSW_FAMAS:         copy( szWpnName, len, "famas"		)

		case CSW_M249:          copy( szWpnName, len, "m249"		)

		case CSW_HEGRENADE:     copy( szWpnName, len, "grenade"		)
		
		case CSW_WORLDSPAWN:    copy( szWpnName, len, "world"		)

		case CSW_LIGHTNING:     	LANG_GetSkillName( ULTIMATE_CHAINLIGHTNING, 	LANG_SERVER, szWpnName, len, 8	)
		case CSW_IMMOLATE:			LANG_GetSkillName( ULTIMATE_IMMOLATE,			LANG_SERVER, szWpnName, len, 10	)
		case CSW_SERPENTWARD:   	LANG_GetSkillName( ABILITY_SERPENTWARD, 		LANG_SERVER, szWpnName, len, 12	)
		case CSW_SMITE:				LANG_GetSkillName( SKILL_SMITE, 				LANG_SERVER, szWpnName, len, 13	)
		case CSW_THORNS:			LANG_GetSkillName( SKILL_THORNS, 				LANG_SERVER, szWpnName, len, 14	)
		case CSW_BLASTWAVE:			LANG_GetSkillName( SKILL_BLASTWAVE,		 		LANG_SERVER, szWpnName, len, 16	)
		case CSW_SERPENTSTING:		LANG_GetSkillName( SKILL_SERPENTSTING,			LANG_SERVER, szWpnName, len, 18	)
		case CSW_ARCANESHOT:		LANG_GetSkillName( SKILL_ARCANESHOT,			LANG_SERVER, szWpnName, len, 19	)
		case CSW_BANISH:			LANG_GetSkillName( SKILL_BANISH, 				LANG_SERVER, szWpnName, len, 20	)
		case CSW_ENTANGLE:			LANG_GetSkillName( ULTIMATE_ENTANGLE,			LANG_SERVER, szWpnName, len, 21	)
		case CSW_CRITICAL_GRENADE:	LANG_GetSkillName( SKILL_CRITICALGRENADE,		LANG_SERVER, szWpnName, len, 22	)
		case CSW_FROSTNOVA_GRENADE:	LANG_GetSkillName( SKILL_FROSTNOVA,				LANG_SERVER, szWpnName, len, 23	)
	}
}



stock UTIL_ClearHudChannel( id, iChannel )
{
	set_hudmessage( 0, 0, 0, 0.0, 0.0, 0, 0.0, 0.0, 0.0, 0.0, iChannel )
	show_hudmessage( id, "" )
}



stock UTIL_GetWeaponIndex( ent )
{
	static classname[17], index

	if( !pev_valid( ent ) )
		return CSW_WORLDSPAWN
		
	index = pev( ent, pev_iuser1 )
	if( CSW_WAR3_MIN < index < CSW_WAR3_MAX )
		return index

	pev( ent, pev_classname, classname, 16 )

	if( equali( classname, "env_explosion" ) )
		return CSW_C4

	if( equal( classname, "grenade") )
	{
		if( get_pdata_int( ent, 96 ) & (1<<8) )
			return CSW_C4
		
		new bits = get_pdata_int( ent, 114 )
		if( bits & (1<<0) )
			return CSW_HEGRENADE
		else if (bits & (1<<1))
			return CSW_SMOKEGRENADE
		else if (!bits)
			return CSW_FLASHBANG
	}
	
	if( equal( classname, "critical grenade") )
		return CSW_HEGRENADE

	if( is_user_alive(ent) )
		return get_user_weapon( ent )

	return CSW_WORLDSPAWN
}



//-------------------------------------------
// UTIL_GetUserNearAim
//
// Returns user near the aim line with some room for error, 0 if none is found
//-------------------------------------------
stock UTIL_GetUserNearAim( id, iTargetTeam )
{
	static Float:vOrigin[3], Float:vNormal[3], Float:vDest[3], Float:view_ofs[3]
	new hTrace, iTargetID

	pev( id, pev_origin, vOrigin )
	pev( id, pev_view_ofs, view_ofs )
	pev( id, pev_v_angle, vNormal )

	engfunc( EngFunc_MakeVectors, vNormal )
	global_get( glb_v_forward, vNormal )

	xs_vec_add( vOrigin, view_ofs, vOrigin )
	xs_vec_mul_scalar( vNormal, 8192.0, vDest )
	xs_vec_add( vOrigin, vDest, vDest )

	engfunc( EngFunc_TraceLine, vOrigin, vDest, DONT_IGNORE_MONSTERS, id, hTrace)
	iTargetID = get_tr2( hTrace, TR_pHit )

	// Direct hit on something
	if( IsValidUser( iTargetID ) )
	{
		if( is_user_alive( iTargetID ) && PlayerInfo[iTargetID][PI_TeamID] == iTargetTeam )
			return iTargetID
	}

	// No hit, see if we can find the closest team member thats near the trace line
	static Float:vTargetOrigin[3], Float:vRay[3],Float:vTmp[3], Float:vTmp2[3], Float:vMins[3], Float:vMaxs[3]
	static Float:fInvDot, Float:fCmp, Float:t, Float:fDistance, Float:theta, Float:fDistToCaster
	new iBestID, Float:fBestDistance, Float:fBestDistToCaster

	get_tr2( hTrace, TR_vecEndPos, vDest )

	xs_vec_sub( vDest, vOrigin, vRay )
	xs_vec_normalize( vRay, vNormal )
	fInvDot = 1.0 / xs_vec_dot( vRay, vRay )

	for( new i = 0 ; i < g_NumTeamPlayers[iTargetTeam] ; i++ )
	{
		iTargetID = g_SortedTeams[iTargetTeam][i]
		
		if( iTargetID == id || !is_user_alive( iTargetID ) )
			continue

		pev( iTargetID, pev_origin, vTargetOrigin )

		xs_vec_sub( vTargetOrigin, vOrigin, vTmp )
		fCmp = 16.0 + xs_vec_len(vTmp) * 0.02
		xs_vec_normalize( vTmp, vTmp2 )

		theta = xs_vec_dot( vTmp2, vNormal )
		if( theta < 0.9 )
			continue

		t = floatmin( xs_vec_dot( vTmp, vRay ) * fInvDot, 1.0 )
		vTmp[0] = vOrigin[0] + t * vRay[0]
		vTmp[1] = vOrigin[1] + t * vRay[1]
		vTmp[2] = vOrigin[2] + t * vRay[2]

		pev( iTargetID, pev_mins, vMins )
		pev( iTargetID, pev_maxs, vMaxs )
		xs_vec_add( vMins, vTargetOrigin, vMins )
		xs_vec_add( vMaxs, vTargetOrigin, vMaxs )
		vMaxs[2] -= 6.0

		vTargetOrigin[0] = floatclamp( vTmp[0], vMins[0], vMaxs[0] )
		vTargetOrigin[1] = floatclamp( vTmp[1], vMins[1], vMaxs[1] )
		vTargetOrigin[2] = floatclamp( vTmp[2], vMins[2], vMaxs[2] )

		// Diagnostic lines
//		static vStart[3], vEnd[3]
//		FVecIVec( vOrigin, vStart )
//		vStart[2] -= 16
//		FVecIVec( vTmp, vEnd )
//		Create_TE_BEAMPOINTS( vStart, vEnd, g_spr_zbeam1, 0, 0, 100 )
//		FVecIVec( vTargetOrigin, vStart )
//		FVecIVec( vTmp, vEnd )
//		Create_TE_BEAMPOINTS( vStart, vEnd, g_spr_zbeam1, 0, 0, 100 )

		fDistance = get_distance_f( vTargetOrigin, vTmp )

		if( fDistance < fCmp && (fDistance <= fBestDistance || fBestDistance == 0.0) )
		{
			fDistToCaster = get_distance_f( vTargetOrigin, vOrigin )

			if( fDistance == fBestDistance && ( fDistToCaster < fBestDistToCaster || fBestDistToCaster == 0.0 ) )
			{
				iBestID = iTargetID
				fBestDistance = fDistance
				fBestDistToCaster = fDistToCaster
			}
			else if( fDistance < fBestDistance || fBestDistToCaster == 0.0 )
			{
				iBestID = iTargetID
				fBestDistance = fDistance
				fBestDistToCaster = fDistToCaster
			}
		}
	}

	return iBestID
}



//-------------------------------------------
// UTIL_FindFreeSpawn
//
// Find a free spawn!
//-------------------------------------------
UTIL_FindFreeSpawn( id, bReverseTeam = false )
{
	static const g_szSpawnEnt[2][] 	= { "info_player_start", "info_player_deathmatch" }

	new iPlayersInVicinity, iSpawnID, iEntList[1], vOrigin[3]
	new ent = -1
	new Float:fSpawnOrigin[3]
	new Float:fVicinity = 96.0
	new bool:bFound = false
	
	new iTeam = PlayerInfo[id][PI_TeamID]

	// Reverse the team IDs (i.e. Mole would want this)
	if ( bReverseTeam )
		iTeam = ( iTeam == TEAM_CT ) ? TEAM_T : TEAM_CT

	// Need to determine which spawn point to look for based on the user's team
	iSpawnID = ( iTeam == TEAM_CT ) ? 0 : 1

	// Loop through each ent until we find a spawn entity that we want
	do
	{
		ent = fm_find_ent_by_class( ent, g_szSpawnEnt[iSpawnID] )
		
		// Valid ent found
		if ( ent != 0 )
		{
			pev( ent, pev_origin, fSpawnOrigin )
			
			// Convert float vector to int vector
			FVecIVec( fSpawnOrigin, vOrigin )

			// Check to see if there are players in this spawn
			iPlayersInVicinity = fm_find_sphere_class( 0, "player", fVicinity, iEntList, 1, fSpawnOrigin )
			
			// We have a free spawn!!
			if ( iPlayersInVicinity == 0 )
			{
				// Make sure it isn't reserved
				if ( !SHARED_SpawnReserved( ent ) )
				{
					// Then we need to reserve it :)
					g_iSpawnReserved[g_iSpawnInc++] = ent
					bFound = true
				}
			}
		}
	} while ( ent && !bFound )
	
	// Reset the spawn points...
	if( !task_exists( TASK_RESETSPAWNS ) )
		set_task( 0.3, "_SHARED_SpawnReset", TASK_RESETSPAWNS )


	// Failed, nothing found
	if( !bFound )
		return -1
	
	// Otherwise we found something!
	return ent
}
